<template>
  <div class="visualization-container">
    <!-- 主渲染画布 -->
    <canvas ref="renderCanvas" class="render-canvas"></canvas>

    <!-- 控制面板 -->
    <div class="control-panel">
      <div class="panel-section">
        <h3>地形渲染控制</h3>

        <div class="stats-display">
          <div class="stat-item">
            <span class="stat-label">渲染点数:</span>
            <span class="stat-value">{{ formatNumber(visiblePoints) }}</span>
          </div>
          <div class="stat-item">
            <span class="stat-label">帧率:</span>
            <span class="stat-value">{{ currentFPS }} FPS</span>
          </div>
          <div class="stat-item">
            <span class="stat-label">内存使用:</span>
            <span class="stat-value">{{ formatMemory(memoryUsage) }}</span>
          </div>
        </div>
      </div>

      <div class="panel-section">
        <h4>渲染设置</h4>
        <div class="setting-group">
          <label>细节层次: {{ lodLevel }}</label>
          <input type="range" v-model="lodLevel" min="0" max="3" step="1">
        </div>
        <div class="setting-group">
          <label>视距: {{ viewDistance }}m</label>
          <input type="range" v-model="viewDistance" min="100" max="10000" step="100">
        </div>
        <div class="setting-group">
          <label>点大小: {{ pointSize }}px</label>
          <input type="range" v-model="pointSize" min="1" max="10" step="0.5">
        </div>
      </div>

      <div class="panel-section">
        <h4>数据管理</h4>
        <div class="data-controls">
          <button @click="loadTerrainData" class="control-button">
            📁 加载地形数据
          </button>
          <button @click="generateProcedural" class="control-button">
            🌀 生成程序地形
          </button>
          <button @click="clearData" class="control-button">
            🧹 清空数据
          </button>
        </div>
      </div>

      <div class="panel-section">
        <h4>可视化模式</h4>
        <div class="visualization-modes">
          <label>
            <input type="radio" v-model="visualizationMode" value="elevation">
            高程着色
          </label>
          <label>
            <input type="radio" v-model="visualizationMode" value="slope">
            坡度分析
          </label>
          <label>
            <input type="radio" v-model="visualizationMode" value="heatmap">
            热力图
          </label>
        </div>
      </div>
    </div>

    <!-- 加载进度 -->
    <div v-if="isLoading" class="loading-overlay">
      <div class="progress-container">
        <div class="progress-bar">
          <div class="progress-fill" :style="progressStyle"></div>
        </div>
        <div class="progress-text">
          加载中: {{ loadProgress }}% - {{ loadStatus }}
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import { GPUComputationRenderer } from 'three/addons/misc/GPUComputationRenderer.js'
import { PLYLoader } from 'three/addons/loaders/PLYLoader.js'

// 地形分块管理器
class TerrainTileManager {
  constructor(renderer, camera) {
    this.renderer = renderer
    this.camera = camera
    this.tiles = new Map()
    this.visibleTiles = new Set()
    this.loadQueue = []
    this.unloadQueue = []

    this.tileSize = 256
    this.maxZoomLevel = 16
    this.loadDistance = 1000
  }

  // 更新可见瓦片
  updateVisibleTiles() {
    const cameraPosition = this.camera.position
    const frustum = new THREE.Frustum()
    frustum.setFromProjectionMatrix(
      new THREE.Matrix4().multiplyMatrices(
        this.camera.projectionMatrix,
        this.camera.matrixWorldInverse
      )
    )

    this.visibleTiles.clear()

    // 计算当前视野范围内的瓦片
    for (const [tileKey, tile] of this.tiles) {
      if (
        this.isTileInFrustum(tile, frustum) &&
        this.isTileInRange(tile, cameraPosition)
      ) {
        this.visibleTiles.add(tileKey)
        tile.setVisible(true)
      } else {
        tile.setVisible(false)
      }
    }

    this.scheduleTileLoading()
  }

  // 调度瓦片加载
  async scheduleTileLoading() {
    const tilesToLoad = this.calculateTilesToLoad()

    for (const tileInfo of tilesToLoad) {
      if (!this.tiles.has(tileInfo.key)) {
        this.loadQueue.push(tileInfo)
      }
    }

    await this.processLoadQueue()
    this.processUnloadQueue()
  }

  // 处理加载队列
  async processLoadQueue() {
    const MAX_CONCURRENT_LOADS = 3
    const currentLoads = []

    while (
      this.loadQueue.length > 0 &&
      currentLoads.length < MAX_CONCURRENT_LOADS
    ) {
      const tileInfo = this.loadQueue.shift()
      const loadPromise = this.loadTile(tileInfo).finally(() => {
        const index = currentLoads.indexOf(loadPromise)
        if (index > -1) currentLoads.splice(index, 1)
      })

      currentLoads.push(loadPromise)
    }

    await Promise.all(currentLoads)
  }

  // 加载单个瓦片
  async loadTile(tileInfo) {
    const { x, y, z } = tileInfo
    const tileKey = `${x}-${y}-${z}`

    try {
      const tileData = await this.fetchTileData(x, y, z)
      const tileMesh = this.createTileMesh(tileData)

      this.tiles.set(tileKey, {
        mesh: tileMesh,
        position: new THREE.Vector3(x * this.tileSize, 0, y * this.tileSize),
        zoomLevel: z,
        visible: false
      })
    } catch (error) {
      console.error(`Failed to load tile ${tileKey}:`, error)
    }
  }

  // 创建瓦片网格
  createTileMesh(tileData) {
    const geometry = new THREE.BufferGeometry()
    const vertices = new Float32Array(tileData.heightMap.length * 3)

    // 处理高程数据
    for (let i = 0; i < tileData.heightMap.length; i++) {
      const x = i % this.tileSize
      const z = Math.floor(i / this.tileSize)
      vertices[i * 3] = x
      vertices[i * 3 + 1] = tileData.heightMap[i]
      vertices[i * 3 + 2] = z
    }

    geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3))
    geometry.computeVertexNormals()

    const material = new THREE.MeshStandardMaterial({
      vertexColors: true,
      wireframe: false
    })

    return new THREE.Mesh(geometry, material)
  }
}

// 点云渲染系统
class PointCloudSystem {
  constructor(renderer, maxPoints = 1000000) {
    this.renderer = renderer
    this.maxPoints = maxPoints
    this.pointClouds = new Map()
    this.gpuCompute = null

    this.initComputeRenderer()
  }

  initComputeRenderer() {
    this.gpuCompute = new GPUComputationRenderer(
      this.maxPoints,
      1,
      this.renderer
    )
  }

  // 创建点云实例
  createPointCloud(pointsData, options = {}) {
    const pointCloud = new THREE.Points(
      this.createPointGeometry(pointsData),
      this.createPointMaterial(options)
    )

    this.pointClouds.set(pointCloud.uuid, pointCloud)
    return pointCloud
  }

  // 创建点几何体
  createPointGeometry(pointsData) {
    const geometry = new THREE.BufferGeometry()

    // 位置数据
    geometry.setAttribute(
      'position',
      new THREE.BufferAttribute(pointsData.positions, 3)
    )

    // 颜色数据
    if (pointsData.colors) {
      geometry.setAttribute(
        'color',
        new THREE.BufferAttribute(pointsData.colors, 3)
      )
    }

    // 大小数据
    if (pointsData.sizes) {
      geometry.setAttribute(
        'size',
        new THREE.BufferAttribute(pointsData.sizes, 1)
      )
    }

    return geometry
  }

  // 创建点材质
  createPointMaterial(options) {
    return new THREE.PointsMaterial({
      size: options.size || 2,
      sizeAttenuation: true,
      vertexColors: true,
      transparent: true,
      opacity: 0.8
    })
  }

  // GPU加速点云更新
  async updatePointsGPU(pointCloud, newData) {
    const positionVariable = this.gpuCompute.addVariable(
      'texturePosition',
      this.positionShader,
      new Float32Array(newData.positions)
    )

    this.gpuCompute.setVariableDependencies(positionVariable, [
      positionVariable
    ])
    this.gpuCompute.init()

    // 执行计算
    this.gpuCompute.compute()

    // 更新几何体
    const positionTexture =
      this.gpuCompute.getCurrentRenderTarget(positionVariable).texture

    this.updateGeometryFromTexture(pointCloud.geometry, positionTexture)
  }

  // 从纹理更新几何体
  updateGeometryFromTexture(geometry, texture) {
    const readBuffer = new Float32Array(this.maxPoints * 4)
    this.renderer.readRenderTargetPixels(
      texture,
      0,
      0,
      this.maxPoints,
      1,
      readBuffer
    )

    geometry.attributes.position.array = readBuffer
    geometry.attributes.position.needsUpdate = true
  }
}
//实时地形变形系统
class TerrainDeformationSystem {
  constructor(renderer, terrainMesh) {
    this.renderer = renderer;
    this.terrainMesh = terrainMesh;
    this.deformationData = null;
    this.gpuCompute = null;

    this.initDeformationSystem();
  }

  initDeformationSystem() {
    // 初始化GPU计算
    this.gpuCompute = new GPUComputationRenderer(
      this.terrainMesh.geometry.attributes.position.count,
      1,
      this.renderer
    );

    // 创建高度场纹理
    this.createHeightfieldTexture();
  }

  // 应用实时变形
  applyDeformation(position, radius, intensity) {
    const deformationShader = `
      uniform vec3 deformationCenter;
      uniform float deformationRadius;
      uniform float deformationIntensity;

      void main() {
        vec2 uv = gl_FragCoord.xy / resolution.xy;
        vec4 heightData = texture2D(heightTexture, uv);

        float distance = length(position - deformationCenter);
        if (distance < deformationRadius) {
          float factor = 1.0 - smoothstep(0.0, deformationRadius, distance);
          heightData.y += deformationIntensity * factor;
        }

        gl_FragColor = heightData;
      }
    `;

    // 执行GPU变形计算
    this.executeDeformationShader(deformationShader, {
      deformationCenter: position,
      deformationRadius: radius,
      deformationIntensity: intensity
    });
  }

  // 执行变形着色器
  executeDeformationShader(shaderCode, uniforms) {
    const variable = this.gpuCompute.addVariable(
      'heightTexture',
      shaderCode,
      this.terrainMesh.geometry.attributes.position.array
    );

    // 设置uniforms
    for (const [name, value] of Object.entries(uniforms)) {
      variable.material.uniforms[name] = { value };
    }

    this.gpuCompute.compute();
    this.updateTerrainGeometry();
  }
}
//流式数据加载器
class StreamDataLoader {
  constructor(maxCacheSize = 5000000) {
    this.maxCacheSize = maxCacheSize;
    this.dataCache = new Map();
    this.loadQueue = [];
    this.currentSize = 0;
  }

  async loadDataChunk(url, priority = 0) {
    // 检查缓存
    if (this.dataCache.has(url)) {
      return this.dataCache.get(url);
    }

    // 加入加载队列
    const loadTask = {
      url,
      priority,
      promise: this.fetchChunkData(url)
    };

    this.loadQueue.push(loadTask);
    this.loadQueue.sort((a, b) => b.priority - a.priority);

    return this.processLoadQueue();
  }

  async processLoadQueue() {
    const MAX_CONCURRENT_LOADS = 2;
    const currentLoads = [];

    while (this.loadQueue.length > 0 && currentLoads.length < MAX_CONCURRENT_LOADS) {
      const task = this.loadQueue.shift();
      const loadPromise = task.promise.then(data => {
        this.cacheData(task.url, data);
        return data;
      });

      currentLoads.push(loadPromise);
    }

    return Promise.all(currentLoads);
  }

  cacheData(url, data) {
    const dataSize = this.calculateDataSize(data);

    // 检查缓存空间
    if (this.currentSize + dataSize > this.maxCacheSize) {
      this.evictCache();
    }

    this.dataCache.set(url, data);
    this.currentSize += dataSize;
  }

  evictCache() {
    // LRU缓存淘汰策略
    const entries = Array.from(this.dataCache.entries());
    entries.sort((a, b) => a[1].lastAccessed - b[1].lastAccessed);

    let freedSize = 0;
    while (freedSize < this.maxCacheSize * 0.2 && entries.length > 0) {
      const [url, data] = entries.shift();
      const dataSize = this.calculateDataSize(data);

      this.dataCache.delete(url);
      this.currentSize -= dataSize;
      freedSize += dataSize;
    }
  }
}


export default {
  name: 'LargeScaleVisualization',
  setup() {
    const renderCanvas = ref(null)
    const isLoading = ref(false)
    const loadProgress = ref(0)
    const loadStatus = ref('')
    const currentFPS = ref(0)
    const visiblePoints = ref(0)
    const memoryUsage = ref(0)
    const lodLevel = ref(1)
    const viewDistance = ref(1000)
    const pointSize = ref(2)
    const visualizationMode = ref('elevation')

    let scene, camera, renderer, controls
    let terrainManager, pointCloudSystem
    let stats, clock
    let frameCount = 0
    let lastFpsUpdate = 0

    // 初始化Three.js场景
    const initScene = async () => {
      // 创建场景
      scene = new THREE.Scene()
      scene.background = new THREE.Color(0x0a0a0a)

      // 创建相机
      camera = new THREE.PerspectiveCamera(
        75,
        window.innerWidth / window.innerHeight,
        0.1,
        10000
      )
      camera.position.set(0, 500, 1000)

      // 创建渲染器
      renderer = new THREE.WebGLRenderer({
        canvas: renderCanvas.value,
        antialias: true,
        powerPreference: 'high-performance'
      })

      renderer.setSize(window.innerWidth, window.innerHeight)
      renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))

      // 添加控制器
      controls = new OrbitControls(camera, renderer.domElement)
      controls.enableDamping = true
      controls.dampingFactor = 0.05
      controls.minDistance = 100
      controls.maxDistance = 5000

      // 初始化管理器
      terrainManager = new TerrainTileManager(renderer, camera)
      pointCloudSystem = new PointCloudSystem(renderer)

      // 添加灯光
      setupLighting()

      // 启动渲染循环
      clock = new THREE.Clock()
      animate()
    }

    // 设置灯光
    const setupLighting = () => {
      const ambientLight = new THREE.AmbientLight(0x404040, 0.6)
      scene.add(ambientLight)

      const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8)
      directionalLight.position.set(1000, 2000, 500)
      directionalLight.castShadow = true
      directionalLight.shadow.mapSize.set(2048, 2048)
      scene.add(directionalLight)

      const hemisphereLight = new THREE.HemisphereLight(0x4477ff, 0x224433, 0.4)
      scene.add(hemisphereLight)
    }

    // 加载地形数据
    const loadTerrainData = async () => {
      isLoading.value = true
      loadStatus.value = '正在加载地形数据...'

      try {
        // 模拟大规模地形数据加载
        const terrainData = await generateMockTerrainData(1024, 1024)
        const terrainMesh = createTerrainMesh(terrainData)

        scene.add(terrainMesh)
        loadProgress.value = 100
      } catch (error) {
        console.error('地形数据加载失败:', error)
      } finally {
        isLoading.value = false
      }
    }

    // 生成程序地形
    const generateProcedural = async () => {
      isLoading.value = true
      loadStatus.value = '生成程序地形...'

      // 使用噪声函数生成地形
      const size = 512
      const heightData = new Float32Array(size * size)

      for (let i = 0; i < size * size; i++) {
        const x = i % size
        const z = Math.floor(i / size)
        heightData[i] = generateHeight(x, z, size)
      }

      const geometry = createTerrainGeometry(heightData, size)
      const material = new THREE.MeshStandardMaterial({
        vertexColors: true,
        wireframe: false
      })

      const terrain = new THREE.Mesh(geometry, material)
      scene.add(terrain)

      isLoading.value = false
    }

    // 生成高度数据
    const generateHeight = (x, z, size) => {
      // 使用多频噪声生成自然地形
      let height = 0
      let frequency = 0.01
      let amplitude = 50

      for (let i = 0; i < 4; i++) {
        height += noise.simplex2(x * frequency, z * frequency) * amplitude
        frequency *= 2
        amplitude *= 0.5
      }

      return height
    }

    // 创建地形几何体
    const createTerrainGeometry = (heightData, size) => {
      const geometry = new THREE.PlaneGeometry(size, size, size - 1, size - 1)
      const vertices = geometry.attributes.position.array

      // 应用高度数据
      for (let i = 0, j = 0; i < vertices.length; i += 3, j++) {
        vertices[i + 1] = heightData[j]
      }

      geometry.computeVertexNormals()
      return geometry
    }

    // 清空数据
    const clearData = () => {
      scene.traverse(object => {
        if (object.isMesh || object.isPoints) {
          scene.remove(object)
          disposeObject(object)
        }
      })

      visiblePoints.value = 0
      memoryUsage.value = 0
    }

    // 释放对象资源
    const disposeObject = object => {
      if (object.geometry) {
        object.geometry.dispose()
      }
      if (object.material) {
        if (Array.isArray(object.material)) {
          object.material.forEach(m => m.dispose())
        } else {
          object.material.dispose()
        }
      }
    }

    // 动画循环
    const animate = () => {
      requestAnimationFrame(animate)

      const deltaTime = clock.getDelta()

      // 更新控制器
      controls.update()

      // 更新地形管理器
      if (terrainManager) {
        terrainManager.updateVisibleTiles()
      }

      // 更新性能统计
      updatePerformanceStats(deltaTime)

      // 渲染场景
      renderer.render(scene, camera)
    }

    // 更新性能统计
    const updatePerformanceStats = deltaTime => {
      frameCount++
      lastFpsUpdate += deltaTime

      if (lastFpsUpdate >= 1.0) {
        currentFPS.value = Math.round(frameCount / lastFpsUpdate)

        // 计算可见点数
        visiblePoints.value = calculateVisiblePoints()

        // 估算内存使用
        memoryUsage.value = estimateMemoryUsage()

        frameCount = 0
        lastFpsUpdate = 0
      }
    }

    // 计算可见点数
    const calculateVisiblePoints = () => {
      let count = 0
      scene.traverse(object => {
        if (object.isPoints) {
          count += object.geometry.attributes.position.count
        }
      })
      return count
    }

    // 估算内存使用
    const estimateMemoryUsage = () => {
      let total = 0
      scene.traverse(object => {
        if (object.isMesh || object.isPoints) {
          if (object.geometry) {
            total += object.geometry.attributes.position.array.byteLength
            if (object.geometry.attributes.color) {
              total += object.geometry.attributes.color.array.byteLength
            }
          }
        }
      })
      return total
    }

    // 格式化数字
    const formatNumber = num => {
      if (num >= 1000000) {
        return (num / 1000000).toFixed(1) + 'M'
      } else if (num >= 1000) {
        return (num / 1000).toFixed(1) + 'K'
      }
      return num.toString()
    }

    // 格式化内存大小
    const formatMemory = bytes => {
      if (bytes >= 1024 * 1024) {
        return (bytes / (1024 * 1024)).toFixed(1) + ' MB'
      } else if (bytes >= 1024) {
        return (bytes / 1024).toFixed(1) + ' KB'
      }
      return bytes + ' B'
    }

    // 进度条样式
    const progressStyle = computed(() => ({
      width: `${loadProgress.value}%`
    }))

    // 响应式设置
    watch(viewDistance, newDistance => {
      camera.far = newDistance
      camera.updateProjectionMatrix()
    })

    watch(lodLevel, newLevel => {
      // 更新LOD级别
      if (terrainManager) {
        terrainManager.setLODLevel(newLevel)
      }
    })

    onMounted(() => {
      initScene()
      window.addEventListener('resize', handleResize)
    })

    onUnmounted(() => {
      if (renderer) {
        renderer.dispose()
      }
      window.removeEventListener('resize', handleResize)
    })

    const handleResize = () => {
      if (!camera || !renderer) return

      camera.aspect = window.innerWidth / window.innerHeight
      camera.updateProjectionMatrix()
      renderer.setSize(window.innerWidth, window.innerHeight)
    }

    return {
      renderCanvas,
      isLoading,
      loadProgress,
      loadStatus,
      currentFPS,
      visiblePoints,
      memoryUsage,
      lodLevel,
      viewDistance,
      pointSize,
      visualizationMode,
      progressStyle,
      loadTerrainData,
      generateProcedural,
      clearData,
      formatNumber,
      formatMemory
    }
  }
}
</script>

<style scoped>
.visualization-container {
  width: 100%;
  height: 100vh;
  position: relative;
  background: #000;
}

.render-canvas {
  width: 100%;
  height: 100%;
  display: block;
}

.control-panel {
  position: absolute;
  top: 20px;
  right: 20px;
  width: 300px;
  background: rgba(0, 0, 0, 0.8);
  padding: 20px;
  border-radius: 10px;
  color: white;
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.panel-section {
  margin-bottom: 20px;
  padding-bottom: 15px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.panel-section:last-child {
  border-bottom: none;
}

.panel-section h3 {
  color: #00ffff;
  margin-bottom: 15px;
  font-size: 16px;
}

.panel-section h4 {
  color: #00ff88;
  margin-bottom: 12px;
  font-size: 14px;
}

.stats-display {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.stat-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px 0;
}

.stat-label {
  color: #ccc;
  font-size: 12px;
}

.stat-value {
  color: #00ffff;
  font-weight: bold;
  font-size: 12px;
}

.setting-group {
  margin-bottom: 12px;
}

.setting-group label {
  display: block;
  margin-bottom: 5px;
  color: #ccc;
  font-size: 12px;
}

.setting-group input[type='range'] {
  width: 100%;
  height: 4px;
  background: #444;
  border-radius: 2px;
  outline: none;
}

.data-controls {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.control-button {
  padding: 10px;
  border: none;
  border-radius: 5px;
  background: linear-gradient(45deg, #667eea, #764ba2);
  color: white;
  cursor: pointer;
  font-size: 12px;
  transition: transform 0.2s;
}

.control-button:hover {
  transform: translateY(-1px);
}

.visualization-modes {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.visualization-modes label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: #ccc;
  cursor: pointer;
}

.visualization-modes input[type='radio'] {
  margin: 0;
}

.loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.7);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.progress-container {
  width: 300px;
  text-align: center;
}

.progress-bar {
  width: 100%;
  height: 6px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 3px;
  overflow: hidden;
  margin-bottom: 10px;
}

.progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #00ffff, #0088ff);
  transition: width 0.3s ease;
  border-radius: 3px;
}

.progress-text {
  color: #00ffff;
  font-size: 14px;
}
</style>
